package com.xingchi.tornado.mybatisplus.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.IllegalSQLInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.xingchi.tornado.mybatisplus.handler.MyBatisPlusMetaObjectHandler;
import com.xingchi.tornado.mybatisplus.plugins.DecryptResultSetHandler;
import com.xingchi.tornado.mybatisplus.plugins.DefaultEncryptor;
import com.xingchi.tornado.mybatisplus.plugins.EncryptDecryptInterceptor;
import com.xingchi.tornado.mybatisplus.plugins.SqlLogInterceptor;
import com.xingchi.tornado.unique.provider.impl.SnowflakeProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import javax.annotation.PreDestroy;

/**
 * MyBatis-Plus配置类
 * 提供各种插件和配置的Bean定义
 *
 * @author xingchi
 * @date 2023/5/21 20:40
 * @modified xingchi
 */
@Configuration
@EnableConfigurationProperties(value = MybatisPlusProperties.class)
public class MyBatisPlusConfig {

    private static final Logger log = LoggerFactory.getLogger(MyBatisPlusConfig.class);

    private SqlLogInterceptor sqlLogInterceptor;

    /**
     * 注册MybatisPlusInterceptor
     * 包含分页、乐观锁、防止全表更新与删除等功能
     *
     * @param properties 配置属性
     * @return MybatisPlusInterceptor实例
     */
    @Bean
    @ConditionalOnMissingBean
    public MybatisPlusInterceptor mybatisPlusInterceptor(MybatisPlusProperties properties) {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 添加分页插件
        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(properties.getDbType());
        paginationInterceptor.setMaxLimit(properties.getMaxLimit());
        paginationInterceptor.setOverflow(properties.isOverflow());
        interceptor.addInnerInterceptor(paginationInterceptor);

        // 乐观锁插件
        if (properties.isOptimisticLockerEnabled()) {
            interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
            log.info("已启用 MyBatis-Plus 乐观锁插件");
        }

        // 防止全表更新与删除插件
        if (properties.isBlockAttackEnabled()) {
            interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
            log.info("已启用 MyBatis-Plus 防全表更新与删除插件");
        }

        // 非法SQL拦截插件
        if (properties.isIllegalSqlEnabled()) {
            interceptor.addInnerInterceptor(new IllegalSQLInnerInterceptor());
            log.info("已启用 MyBatis-Plus 非法SQL拦截插件");
        }

        return interceptor;
    }

    /**
     * SQL日志拦截器
     * 用于记录SQL执行日志
     *
     * @param properties 配置属性
     * @return SqlLogInterceptor实例
     */
    @Bean
    @ConditionalOnProperty(value = "xingchi.tornado.mybatis-plus.logging.enable", havingValue = "true")
    @ConditionalOnMissingBean
    public SqlLogInterceptor sqlLogInterceptor(MybatisPlusProperties properties) {
        SqlLogInterceptor interceptor = new SqlLogInterceptor();
        this.sqlLogInterceptor = interceptor;
        log.info("已启用 SQL 日志记录");
        return interceptor;
    }

    /**
     * 自定义ID生成器
     *
     * @param snowflakeProvider 雪花算法ID生成器
     * @return CustomIdGenerator实例
     */
    @Bean
    @ConditionalOnMissingBean
    public CustomIdGenerator customIdGenerator(SnowflakeProvider snowflakeProvider) {
        log.info("已配置自定义ID生成器 (基于雪花算法)");
        return new CustomIdGenerator(snowflakeProvider);
    }

    /**
     * MyBatisPlus元对象处理器
     * 用于自动填充字段
     *
     * @param snowflakeProvider 雪花算法ID生成器
     * @return MyBatisPlusMetaObjectHandler实例
     */
    @Bean
    @ConditionalOnMissingBean
    public MyBatisPlusMetaObjectHandler myBatisPlusMetaObjectHandler(SnowflakeProvider snowflakeProvider) {
        log.info("已配置 MyBatis-Plus 元对象处理器");
        return new MyBatisPlusMetaObjectHandler(snowflakeProvider);
    }

    /**
     * 注册加解密拦截器
     *
     * @param properties 配置属性
     * @return 加解密拦截器实例
     */
    @Bean
    @ConditionalOnProperty(value = "xingchi.tornado.mybatis-plus.encryption-enabled", havingValue = "true")
    @ConditionalOnMissingBean
    public EncryptDecryptInterceptor encryptDecryptInterceptor(MybatisPlusProperties properties) {
        log.info("已启用 数据加解密拦截器");
        return new EncryptDecryptInterceptor(createEncryptor(properties));
    }

    /**
     * 注册结果集解密处理器
     *
     * @param properties 配置属性
     * @return 结果集解密处理器实例
     */
    @Bean
    @ConditionalOnProperty(value = "xingchi.tornado.mybatis-plus.encryption-enabled", havingValue = "true")
    @ConditionalOnMissingBean
    public DecryptResultSetHandler decryptResultSetHandler(MybatisPlusProperties properties) {
        log.info("已启用 查询结果解密处理器");
        return new DecryptResultSetHandler(
            createEncryptor(properties),
            properties.getEncrypt().isAutoDecryptResponse()
        );
    }

    /**
     * 创建加密器
     *
     * @param properties 配置属性
     * @return 加密器实例
     */
    private EncryptDecryptInterceptor.IEncryptor createEncryptor(MybatisPlusProperties properties) {
        String secretKey = properties.getEncrypt().getSecretKey();
        if (StringUtils.hasText(secretKey)) {
            return new DefaultEncryptor(secretKey);
        }
        return new DefaultEncryptor();
    }

    /**
     * 销毁时关闭资源
     */
    @PreDestroy
    public void destroy() {
        if (sqlLogInterceptor != null) {
            sqlLogInterceptor.shutdown();
            log.info("已关闭 SQL 日志拦截器资源");
        }
    }
}
